package com.fit.utils.se;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.ToString;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;

/**
 * 计算数据(捕捞季节)
 * @author hcl
 * @since 2021/4/11
 */
public class TestCalculatingData {

    @Data
    @ToString(exclude="pre")
    public static class StockData{
        /**
         * 日期
         */
        private String date;
        /**
         * 开始价格
         */
        private Double o;
        /**
         * 最高价格
         */
        private Double h;
        /**
         * 最低价格
         */
        private Double l;
        /**
         * 结束价格
         */
        private Double c;

        /**
         * 成交量指标
         */
        private Double vol;

        /**
         * 捕捞季节.绿色线的值
         */
        private Double bljjGreen;
        /**
         * 捕捞季节.红色线的值
         */
        private Double bljjRed;


        /**
         * 资金流入.流量的值
         */
        private Double zjlrFlow;


        /**
         * 当天临时数据存取
         */
        private Map<String,Object> tempData = new HashMap<>();

        /**
         * 上一个周期数据
         */
        private StockData pre;

    }



    public static void main(String[] args) {

        try {
            List<List<Record<String>>> list = ExcelUtil.readExcel(new FileInputStream("C:\\Work\\fit\\0.0.2\\fit-parent\\fit-utils\\fit-utils-se\\src\\main\\java\\com\\fit\\utils\\se\\600028_day.xlsx"),0,null,null);

            AtomicInteger ato = new AtomicInteger(0);
            StockData previousStockData = null;
            for (List<Record<String>> row : list) {
                ato.incrementAndGet();
                if(ato.get() > 4 && row.size() > 20){
                    StockData stockData = new StockData();
                    stockData.setPre(previousStockData);

                    stockData.setDate(row.get(0).toString());
                    stockData.setO(row.get(1).getDouble());
                    stockData.setH(row.get(2).getDouble());
                    stockData.setL(row.get(3).getDouble());
                    stockData.setC(row.get(4).getDouble());
                    //计算不捞季节数据
                    calculatingBljj(stockData);
                    //计算资金流入
                    calculatingZjlr(stockData);

                    System.out.println(stockData);


                    previousStockData = stockData;


                }
            }



        } catch (Exception e) {
            e.printStackTrace();
        }


    }

    /**
     * 计算 资金流入
     * @param stockData
     * @return 
     * @author hcl
     * @since 2021/4/17
     */
    private static void calculatingZjlr(StockData stockData) {

        StockData preStockData = stockData.getPre();
        Double prePjj = 0D;
        Double preHsl = 0D;
        Double pre2Hsl = 0D;
        Double preGjll = null;
        if(preStockData != null){
            prePjj = (Double)preStockData.getTempData().get("zjlr_pjj");
            preHsl = (Double)preStockData.getTempData().get("zjlr_hsl");
            preGjll = (Double)preStockData.getTempData().get("zjlr_gjll");

            StockData pre2StockData = preStockData.getPre();
            if(pre2StockData != null){
                pre2Hsl = (Double)pre2StockData.getTempData().get("zjlr_hsl");
            }
        }

        Double pjj = dma((stockData.getH() + stockData.getL() + stockData.getC() * 2D) / 4D,0.9D,prePjj);
        stockData.getTempData().put("zjlr_pjj", pjj);
        Double qjj = stockData.getVol() / ((stockData.getH() - stockData.getL()) * 2D - Math.abs(stockData.getC() - stockData.getO()));

        Double xvl  = null;
        if(stockData.getC() > 0D){
            xvl = qjj * (stockData.getH() - stockData.getL());
        }else if(stockData.getC() < 0D){
            xvl = qjj * (stockData.getH() - stockData.getO() + (stockData.getC() - stockData.getL()));
        }else{
            xvl = stockData.getVol() / 2D;
        }
        if(stockData.getC() > 0D){
            xvl = xvl + (0D - qjj * (stockData.getH() - stockData.getC() + (stockData.getO() - stockData.getL())));
        }else if(stockData.getC() < 0D){
            xvl = xvl + (0D - qjj * (stockData.getH() - stockData.getL()));
        }else{
            xvl = xvl + (0D - stockData.getVol() / 2D);
        }

        Double hsl = xvl / 20D / 1.15D;
        stockData.getTempData().put("zjlr_hsl", hsl);

        Double gjll = hsl * 0.55D + preHsl * 0.33D + pre2Hsl * 0.22D;
        stockData.getTempData().put("zjlr_gjll", gjll);
        //流量
        Double lljx = ema(gjll,3,preGjll);
        stockData.setZjlrFlow(lljx);
    }




    /**
     * 计算捕捞季节数据
     * @param stockData 当周期数据
     * @author hcl
     * @since 2021/4/12
     */
    public static void calculatingBljj(StockData stockData){
        Double preWy1 = null;
        Double preWy2 = null;
        Double preWy3 = null;
        Double preWy4 = null;
        Double preXys0 = null;

        StockData preStockData = stockData.getPre();
        if(preStockData != null){
            preWy1 = (Double)preStockData.getTempData().get("bljj_wy1");
            preWy2 = (Double)preStockData.getTempData().get("bljj_wy2");
            preWy3 = (Double)preStockData.getTempData().get("bljj_wy3");
            preWy4 = (Double)preStockData.getTempData().get("bljj_wy4");
            preXys0 = (Double)preStockData.getTempData().get("bljj_xys0");
        }

        Double wy1 = (2D * stockData.getC() + stockData.getH() + stockData.getL()) / 3D;
        stockData.getTempData().put("bljj_wy1",wy1);

        Double wy2 = ema(wy1,3, preWy2);
        stockData.getTempData().put("bljj_wy2",wy2);

        Double wy3 = ema(wy2,3, preWy3);
        stockData.getTempData().put("bljj_wy3",wy3);

        Double wy4 = ema(wy3,3, preWy4);
        stockData.getTempData().put("bljj_wy4",wy4);

        if(preWy4 == null){
            preWy4 = 0.001;
        }

        Double xys0 = (wy4 - preWy4) / preWy4 * 100;
        stockData.getTempData().put("bljj_xys0",xys0);

        if(preXys0 == null){
            preXys0 = xys0;
        }
        Double xys1 = ma(Arrays.asList(preXys0,xys0));
        Double xys2 = xys0;

        stockData.setBljjGreen(xys1);
        stockData.setBljjRed(xys2);
    }



    /**
     * DMA(X，A)　 -- dynamic move average
     * 求X的动态移动平均。A 为动态因子
     * 算法：　若Y=DMA(X，A)则 Y=A*X+(1-A)*Y'，其中Y'表示上一周期Y值，A必须小于1。
     * 例如：　DMA(CLOSE，VOL/CAPITAL)　
     * @param x
     * @param a
     * @param prevDma 上一周期的值
     * @return
     * @author hcl
     * @since 2021/4/17
     */
    public static Double dma(Double x, Double a,Double prevDma){
        if(prevDma == null){
            prevDma = 0D;
        }
        return a * x + (1 - a) * prevDma;
    }

    /**
     * 求集合中的平均值
     * @param vals 数据
     * @return 平均值
     * @author hcl
     * @since 2021/4/14
     */
    public static Double ma(List<Double> vals){
        return vals
                .stream()
                .mapToDouble(e->e)
                .sum() / vals.size();
    }


    /**
     * 计算ema,多周期
     * @param vals 每个周期的数据
     * @param n 多少周期的数据平移
     * @param prevEma 上一个周期的ema(如果为第一个周期传入null即可,为了实现分批次调用时使用)
     * @return 多个周期的ema数据
     * @author hcl
     * @since 2021/4/12
     */
    public static List<Double> ema(List<Double> vals, Integer n,Double prevEma){
        List<Double> emas = new LinkedList<>();
        for (Double val : vals) {
            prevEma = ema(val,n,prevEma);
            emas.add(prevEma);
        }
        return emas;
    }


    /**
     * 计算ema,单周期
     * @param val 当周期数据
     * @param n 多少周期的数据平移
     * @param prevEma 上一个周期的ema(如果为第一个周期传入null即可)
     * @return 单个周期的ema数据
     * @author hcl
     * @since 2021/4/12
     */
    public static Double ema(Double val, Integer n,Double prevEma){
        // 第一天ema等于当天最新价
        if(prevEma == null){
            return val;
        }
        //计算今天的ema
        return (2D * val + (n - 1D) * prevEma) / ( n + 1D);
    }

}
